
// ===============================================================================================================
// -*- C++ -*-
//
// MeshOptimize.hpp - Progressive Mesh implementation, based on the algorithms presented here:
// http://www.melax.com/polychop - By Stan Melax.
//
// Copyright (c) 2010 Guilherme R. Lampert
// guilherme.ronaldo.lampert@gmail.com
//
// This code is licenced under the MIT license.
//
// This software is provided "as is" without express or implied
// warranties. You may freely copy and compile this source into
// applications you distribute provided that the copyright text
// above is included in the resulting source code.
//
// ===============================================================================================================

#ifndef __MESH_OPTIMIZE_HPP__
#define __MESH_OPTIMIZE_HPP__

// == External Modules ======

#include "Utility.hpp"
#include "Vector.hpp"
#include "Array.hpp"

// ==========================================================================
// Mesh Optimization Routines And Classes (Used By The ProgressiveMesh Class)
// ==========================================================================

// Optimizing complex polygons in very difficult,
// so we only support triangular meshes for now. No support for mesh UVs as well.

struct Triangle {

	Triangle() { }

	inline Triangle(const unsigned int * v)
	{
		VertexIndex[0] = v[0];
		VertexIndex[1] = v[1];
		VertexIndex[2] = v[2];
	}

	inline bool operator == (const Triangle & r) const
	{
		return ((VertexIndex[0] == r.VertexIndex[0]) &&
				(VertexIndex[1] == r.VertexIndex[1]) &&
				(VertexIndex[2] == r.VertexIndex[2]) );
	}

	unsigned int VertexIndex[3];
};

// This function does the real job running the polygon reduction algorithm.
// It is NOT thread save, since it is using some global data declared in the .cpp
void MeshOptimize(const Array<Vec3> & vertices, const Array<Triangle> & indices, Array<int> & Map, Array<int> & Permutation);

class TriangleEx;
class VertexEx;

typedef Array<VertexEx *> vertex_list_t;
typedef Array<TriangleEx *> triangle_list_t;

template<class T> T MAX(const T & a, const T & b)
{
	return (a > b) ? a : b;
}

template<class T> T MIN(const T & a, const T & b)
{
	return (a < b) ? a : b;
}

// =======================
// Extended Triangle Class
// =======================

class TriangleEx {

public:

	TriangleEx();
	TriangleEx(VertexEx * v0, VertexEx * v1, VertexEx * v2);

	void computeNormal();
	void replaceVertex(VertexEx * vOld, VertexEx * vNew);
	bool hasVertex(const VertexEx * v) const;

	~TriangleEx();

public:

	VertexEx * vertex[3];
	Vec3 normal;
};

// =====================
// Extended Vertex Class
// =====================

class VertexEx {

public:

	VertexEx() : collapse(0) { }
	VertexEx(const Vec3 & v, int iD) : pos(v), id(iD), collapse(0) { }

	void removeIfNonNeighbor(VertexEx * v);
	~VertexEx();

public:

	Vec3 pos;
	int id;

	vertex_list_t adjacent_verts;
	triangle_list_t adjacent_tris;

	float objdist;
	VertexEx * collapse;
};

#endif // __MESH_OPTIMIZE_HPP__
